/***************************************************************************
  A SymbolBrowser plugin for JuffEd editor.

  Copyright: 2010 Aleksander Sokoloff <asokol@mail.ru>


  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License.
  version 2 as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
***************************************************************************/

#include "symbolbrowserview.h"
#include "documentparser.h"
//#include "symbol.h"
#include "items.h"

#include <QDebug>
#include <QVBoxLayout>
#include <QScrollBar>

//#include <QTreeView>
//#include <QStandardItemModel>
#include <QStandardItem>
#include <QMenu>
#include <QAction>

/**********************************************************
 *
 **********************************************************/
SymbolBrowserView::SymbolBrowserView(QWidget * parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
    mSettingsActivateOnSingleClick = false;
    mSettingsDetail = false;
    mSettingsExpand = false;
    mSettingsSort = false;
    mActiveParser = NULL;

    mTreeView = new QTreeView(this);
    mModel = new QStandardItemModel(this);
    mTreeView->setModel(mModel);
    mTreeView->setVerticalScrollMode(QTreeView::ScrollPerPixel);
    mTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(mTreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
    mModel->setHorizontalHeaderLabels(QStringList() << tr("Symbols"));
    this->setWindowTitle(tr("Symbol browser"));

    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->addWidget(mTreeView);
    this->setLayout(layout);

    connect(mTreeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(treeItemClicked(const QModelIndex &)));
    connect(mTreeView, SIGNAL(activated(const QModelIndex &)), this, SLOT(treeItemActivated(const QModelIndex &)));
}


/**********************************************************
 *
 **********************************************************/
SymbolBrowserView::~SymbolBrowserView()
{
}


/*****************************************************************************
 *
 *****************************************************************************/
void SymbolBrowserView::addParser(DocumentParser* parser)
{
    mParsers.append(parser);
    connect(parser, SIGNAL(destroyed(QObject*)), this,  SLOT(parserDestroyed(QObject*)));
}


/*****************************************************************************
 *
 *****************************************************************************/
void SymbolBrowserView::parserDestroyed(QObject * obj)
{
    mParsers.removeAll(static_cast<DocumentParser*>(obj));
}


/*****************************************************************************
 *
 *****************************************************************************/
DocumentParser* SymbolBrowserView::getParserByDocument(QObject* document)
{
    QList<DocumentParser*>::iterator i;
    for (i = mParsers.begin(); i != mParsers.end(); ++i)
    {
        if ((*i)->parent() == document)
        {
            return *i;
        }
    }
    return NULL;
}


/*****************************************************************************
 *
 *****************************************************************************/
QAction* SymbolBrowserView::createRelationAction(const SymbolInfo *symbol, QObject *parent)
{
    QAction *act = new QAction("", parent);
    switch (symbol->type()) {
        case SymbolTypeFunc:  act->setText(tr("Show the definition"));    break;
        default:              act->setText(tr("Show the declaration"));   break;
    }

    act->setData(symbol->line());
    connect(act, SIGNAL(triggered()), this, SLOT(relatedMenuTriggered()));
    return act;
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::showContextMenu(QPoint pos)
{
    Q_UNUSED(pos);

    QMenu menu;

    QModelIndex index = mTreeView->indexAt(pos);
    Item *item = dynamic_cast<Item*>(mModel->itemFromIndex(index));

    if (item)
    {
        if (item->relatedSymbol())
            menu.addAction(createRelationAction(item->relatedSymbol(), &menu));

        menu.addAction(createRelationAction(item, &menu));
        menu.addSeparator();
    }


    QAction actSort(tr("Sort by name"), &menu);
    actSort.setCheckable(true);
    actSort.setEnabled(mActiveParser);
    actSort.setChecked(mActiveParser && mActiveParser->sorted() == Item::SortByName);
    connect(&actSort, SIGNAL(toggled(bool)), this, SLOT(sortByName(bool)));
    menu.addAction(&actSort);

    QAction actDetailed(tr("Display functions parameters"), &menu);
    actDetailed.setCheckable(true);
    actDetailed.setEnabled(mActiveParser);
    actDetailed.setChecked(mActiveParser && mActiveParser->detailed());
    connect(&actDetailed, SIGNAL(toggled(bool)), mActiveParser, SLOT(setDetailed(bool)));
    menu.addAction(&actDetailed);

    menu.exec(QCursor::pos());
}


/*****************************************************************************
 *
 *****************************************************************************/
void SymbolBrowserView::relatedMenuTriggered()
{
    QAction *act = qobject_cast<QAction*>(sender());
    if (!act) return;

    bool ok;
    int lineNum = act->data().toInt(&ok);
    if (ok) skipToLine(lineNum);
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::sortByName(bool value)
{
    if (value)
        mActiveParser->sort(Item::SortByName);
    else
        mActiveParser->sort(Item::SortByLine);
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::setSettingsActivateOnSingleClick(bool value)
{
    mSettingsActivateOnSingleClick = value;
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::setSettingsDetail(bool value)
{
    mSettingsDetail = value;
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::setSettingsExpand(bool value)
{
    mSettingsExpand = value;
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::setSettingsSort(bool value)
{
    mSettingsSort = value;
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::treeItemClicked(const QModelIndex &index)
{
    if (!mActiveParser)
        return;

    if (!mSettingsActivateOnSingleClick)
        return;

    Item *item = dynamic_cast<Item*>(mModel->itemFromIndex(index));
    if (item) skipToLine(item->line());
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::treeItemActivated(const QModelIndex &index)
{
    if (mSettingsActivateOnSingleClick)
        return;

    Item *item = dynamic_cast<Item*>(mModel->itemFromIndex(index));
    if (item) skipToLine(item->line());
}


/**********************************************************
 *
 **********************************************************/
void SymbolBrowserView::skipToLine(int line)
{
    if (line>-1)
        mActiveParser->skipToLine(line);
}
